package org.bookie.framework;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hivemind.ClassResolver;
import org.apache.tapestry.BaseComponent;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.annotations.InitialValue;
import org.apache.tapestry.annotations.InjectObject;
import org.apache.tapestry.annotations.Persist;
import org.apache.tapestry.engine.IEngineService;
import org.apache.tapestry.event.PageAttachListener;
import org.apache.tapestry.event.PageEvent;
import org.apache.tapestry.services.ResponseBuilder;
import org.apache.tapestry.spec.IComponentSpecification;
import org.apache.tapestry.valid.IValidationDelegate;
import org.apache.tapestry.valid.ValidationConstraint;
import org.bookie.core.services.IAuthenticationContext;
import org.bookie.framework.services.NotificationService;

public abstract class CommonBaseComponent extends BaseComponent implements PageAttachListener {

	protected Log log = LogFactory.getLog(getClass());
	
	/**
	 * Getter for the delegate
	 * 
	 * @category injected
	 * @param delegate
	 */
	@InitialValue("new org.bookie.framework.CustomDelegate()")
	public abstract void setDelegate(IValidationDelegate delegate);

	/**
	 * Returns injected {@link NotificationService}
	 * @return
	 */
	@InjectObject("service:bookie.framework.NotificationService")
	public abstract NotificationService getNotificationService();
	
	/**
	 * Injected authentication context.
	 * @return instance of IAuthenticationContext
	 */
	@InjectObject("service:bookie.core.AuthenticationContext")
	public abstract IAuthenticationContext getAuthenticationContext();
	
	/**
	 * Setter for the delegate
	 * 
	 * @return
	 */
	public abstract IValidationDelegate getDelegate();
	
	/**
	 * Propery with flash persistence
	 * 
	 * @param message
	 */
	@Persist("flash")
	public abstract void setMessage(String message);
	
	/**
	 * Getter for the message
	 * 
	 * @return
	 */
	public abstract String getMessage();
	
	/**
	 * Returns an page engine service
	 * 
	 * @return
	 */
	@InjectObject("engine-service:page")
	public abstract IEngineService getPageService();
	
	/**
	 * Get the external service
	 * @return
	 */
	@InjectObject("engine-service:external")
	public abstract IEngineService getExternalService();
	
	
	/**
	 * Injected response builder
	 * @return
	 */
	@InjectObject("service:tapestry.globals.ResponseBuilder")
	public abstract ResponseBuilder getResponseBuilder();
	
	/**
	 * Returns a request cycle
	 * @return
	 */
	@InjectObject("service:tapestry.globals.IRequestCycle")
	public abstract IRequestCycle getRequestCycle();
	

	/**
	 * Recods errror to the delegate with given error message, without any form
	 * component association with {@link ValidationConstraint#CONSISTENCY}
	 * 
	 * @param messageKey
	 */
	protected void recordError(String messageKey) {
		getDelegate().setFormComponent(null);
		String message = getMessages().getMessage(messageKey);
		getDelegate().record(message, ValidationConstraint.CONSISTENCY);
	}
	/**
	 * Format a string using {@link #getMessages()}
	 * @param key the key used to obtain a localized pattern
	 * @param argument1 first argument passed to the formatter
	 */
	public void formatError(String key, String argument1){
		getDelegate().setFormComponent(null);
		String message = getMessages().format(key, argument1);
		getDelegate().record(message, ValidationConstraint.CONSISTENCY);
	}
	
	/**
	 * Get the real class of the component without any tapestry enhancements.
	 * @return class of the page
	 */
	public Class getComponentClass(){
		IComponentSpecification spec = getSpecification();
		String className = spec.getComponentClassName();
		ClassResolver resolver = getRequestCycle().getEngine().getInfrastructure().getClassResolver();
		return resolver.findClass(className);
	}
	
	/**
	 * Updates the given components
	 * @param components components to update
	 */
	public void updateComponents(String... components){
		for(String id:components){
			getResponseBuilder().updateComponent(id);
		}
	}
	
	/**
	 * When page where component is located activated
	 * we need to register it's methods for notification
	 * 
	 */
	public void pageAttached(PageEvent event) {
			log.debug("Registering component " + getIdPath() + " in the listener service");
			getNotificationService().registerListener(this);
	}
}
